Ce tutorial présente le système de coordonnées 2D en C# à travers la création d'un mini-jeu où un escargot doit parcourir un chemin du départ à l'arrivée.
Nous allons créer un jeu simple où :
@ se déplace sur une grilleS jusqu'à l'arrivée EÀ travers 6 étapes progressives, vous apprendrez à :
Console.SetCursorPositionEn mathématiques, on apprend que :
Y
↑
|
| • (3,2)
|
+------→ X
(0,0)
En programmation console (et dans la plupart des systèmes graphiques) :
(0,0)----→ X
|
| • (3,2)
|
↓
Y
Reprendre le projet précédent avec le mune ou créer un nouveau projet Console App nommé SnailGame.
Adapter le contenu de Program.cs avec les éléments suivants :
// Clear the console
Console.Clear();
// Position (0,0) = top-left corner
Console.SetCursorPosition(0, 0);
Console.Write("A");
// Position (10,0) = 10 characters to the right, still at top
Console.SetCursorPosition(10, 0);
Console.Write("B");
// Position (0,5) = left side, 5 lines DOWN (not up!)
Console.SetCursorPosition(0, 5);
Console.Write("C");
// Position (10,5) = 10 right, 5 down
Console.SetCursorPosition(10, 5);
Console.Write("D");
// Wait for key press
Console.SetCursorPosition(0, 10);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
A B
C D
Press any key to exit...
Modifiez le code pour dessiner un carré avec des * aux positions :
Console.SetCursorPosition(x, y);
// ↑ ↑
// | |
// colonne (gauche/droite)
// |
// ligne (haut/bas, inversé !)
x (1er) | Horizontale | 0 = gauche, + = droite |
y (2ème) | Verticale | 0 = haut, + = bas |
Créer une fonction pour afficher l'escargot à une position donnée.
// Snail position
int snailX = 5;
int snailY = 3;
// Main program
Console.Clear();
Console.CursorVisible = false; // Hide the blinking cursor
Snail_Draw(snailX, snailY);
Console.SetCursorPosition(0, 10);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
// ============ SNAIL FUNCTIONS ============
void Snail_Draw(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("@"); // Our snail character
Console.ResetColor();
}
Pour pouvoir déplacer l'escargot, il faut aussi effacer sa position précédente :
void Snail_Clear(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.Write(" "); // Replace with empty space
}
Ajoutez ce code pour voir l'escargot "se déplacer" :
// Snail position
int snailX = 5;
int snailY = 3;
Console.Clear();
Console.CursorVisible = false;
// Draw snail at initial position
Snail_Draw(snailX, snailY);
Console.ReadKey(true);
// Erase snail at old position
Snail_Clear(snailX, snailY);
// Move snail to the right
snailX = snailX + 5;
// Draw snail at new position
Snail_Draw(snailX, snailY);
Console.SetCursorPosition(0, 10);
Console.WriteLine("Snail moved! Press any key to exit...");
Console.ReadKey();
// ============ SNAIL FUNCTIONS ============
void Snail_Draw(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("@");
Console.ResetColor();
}
void Snail_Clear(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.Write(" ");
}
C'est le principe de base de toute animation en programmation !
Permettre au joueur de déplacer l'escargot avec les touches fléchées.
↑ Up
Y--
← Left @ → Right
X-- X++
↓ Down
Y++
// Snail position
int snailX = 10;
int snailY = 5;
// Game boundaries
int minX = 0;
int maxX = 40;
int minY = 0;
int maxY = 15;
// Main program
Console.Clear();
Console.CursorVisible = false;
Game_ShowInstructions();
Snail_Draw(snailX, snailY);
// Game loop
bool playing = true;
while (playing)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
// Store old position
int oldX = snailX;
int oldY = snailY;
// Handle key press
switch (keyInfo.Key)
{
case ConsoleKey.UpArrow:
snailY = snailY - 1; // Move UP = Y decreases!
break;
case ConsoleKey.DownArrow:
snailY = snailY + 1; // Move DOWN = Y increases!
break;
case ConsoleKey.LeftArrow:
snailX = snailX - 1;
break;
case ConsoleKey.RightArrow:
snailX = snailX + 1;
break;
case ConsoleKey.Escape:
playing = false;
break;
}
// Keep snail within boundaries
if (snailX < minX) snailX = minX;
if (snailX > maxX) snailX = maxX;
if (snailY < minY) snailY = minY;
if (snailY > maxY) snailY = maxY;
// Update display only if position changed
if (oldX != snailX || oldY != snailY)
{
Snail_Clear(oldX, oldY);
Snail_Draw(snailX, snailY);
}
}
Console.Clear();
Console.WriteLine("Thanks for playing!");
// ============ FUNCTIONS ============
void Game_ShowInstructions()
{
Console.SetCursorPosition(0, maxY + 2);
Console.WriteLine("Use arrow keys to move the snail. Press ESC to quit.");
Console.WriteLine($"Boundaries: X[{minX}-{maxX}], Y[{minY}-{maxY}]");
}
void Snail_Draw(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("@");
Console.ResetColor();
}
void Snail_Clear(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.Write(" ");
}
while (playing)
{
// 1. Lire l'input
// 2. Mettre à jour la logique
// 3. Afficher
}
C'est le pattern fondamental de tout jeu vidéo !
if (snailX < minX) snailX = minX;
Sans ces vérifications, l'escargot pourrait sortir de l'écran et causer des erreurs.
Ajouter une fonction qui affiche en temps réel la position de l'escargot :
void Game_ShowPosition(int x, int y)
{
Console.SetCursorPosition(0, maxY + 4);
Console.Write($"Position: X={x,3}, Y={y,3} ");
}
Appeler cette fonction après chaque déplacement pour observer comment X et Y changent.
Créer le jeu final avec un point de départ, un point d'arrivée, et une condition de victoire.

// Game configuration
int screenWidth = 50;
int screenHeight = 15;
// Snail position (starts at S)
int snailX = 2;
int snailY = 2;
// Start position
int startX = 2;
int startY = 2;
// End position (goal)
int endX = 45;
int endY = 12;
// Main program
Console.Clear();
Console.CursorVisible = false;
Game_DrawBorder();
Game_DrawStart(startX, startY);
Game_DrawEnd(endX, endY);
Game_ShowInstructions();
Snail_Draw(snailX, snailY);
// Game loop
bool playing = true;
bool won = false;
while (playing)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
int oldX = snailX;
int oldY = snailY;
switch (keyInfo.Key)
{
case ConsoleKey.UpArrow:
snailY = snailY - 1; // UP = Y-- (towards 0)
break;
case ConsoleKey.DownArrow:
snailY = snailY + 1; // DOWN = Y++ (away from 0)
break;
case ConsoleKey.LeftArrow:
snailX = snailX - 1; // LEFT = X--
break;
case ConsoleKey.RightArrow:
snailX = snailX + 1; // RIGHT = X++
break;
case ConsoleKey.Escape:
playing = false;
break;
}
// Keep snail within game area (inside border)
if (snailX < 1) snailX = 1;
if (snailX > screenWidth - 2) snailX = screenWidth - 2;
if (snailY < 1) snailY = 1;
if (snailY > screenHeight - 2) snailY = screenHeight - 2;
// Update display
if (oldX != snailX || oldY != snailY)
{
Snail_Clear(oldX, oldY);
// Redraw start if snail was on it
if (oldX == startX && oldY == startY)
{
Game_DrawStart(startX, startY);
}
Snail_Draw(snailX, snailY);
Game_ShowPosition(snailX, snailY);
// Check win condition
if (snailX == endX && snailY == endY)
{
won = true;
playing = false;
}
}
}
// End game
Console.SetCursorPosition(0, screenHeight + 5);
if (won)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("🎉 CONGRATULATIONS! You reached the goal!");
Console.WriteLine("The snail completed its journey!");
Console.ResetColor();
}
else
{
Console.WriteLine("Game ended. Thanks for playing!");
}
Console.ReadKey();
// ============ GAME FUNCTIONS ============
void Game_DrawBorder()
{
Console.ForegroundColor = ConsoleColor.DarkGray;
// Top and bottom borders
for (int x = 0; x < screenWidth; x++)
{
Console.SetCursorPosition(x, 0);
Console.Write("#");
Console.SetCursorPosition(x, screenHeight - 1);
Console.Write("#");
}
// Left and right borders
for (int y = 0; y < screenHeight; y++)
{
Console.SetCursorPosition(0, y);
Console.Write("#");
Console.SetCursorPosition(screenWidth - 1, y);
Console.Write("#");
}
Console.ResetColor();
}
void Game_DrawStart(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("S");
Console.ResetColor();
}
void Game_DrawEnd(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("E");
Console.ResetColor();
}
void Game_ShowInstructions()
{
Console.SetCursorPosition(0, screenHeight + 1);
Console.WriteLine("Move the snail @ from S (Start) to E (End)");
Console.WriteLine("Use arrow keys. Press ESC to quit.");
}
void Game_ShowPosition(int x, int y)
{
Console.SetCursorPosition(0, screenHeight + 4);
Console.Write($"Position: X={x,3} (left/right), Y={y,3} (top/down) ");
}
// ============ SNAIL FUNCTIONS ============
void Snail_Draw(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("@");
Console.ResetColor();
}
void Snail_Clear(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.Write(" ");
}
| Dessine le cadre du jeu |
| Affiche le point de départ "S" |
| Affiche le point d'arrivée "E" |
| Affiche les instructions |
| Affiche les coordonnées actuelles |
| Dessine l'escargot |
| Efface l'escargot |
if (snailX == endX && snailY == endY)
{
won = true;
playing = false;
}
Le joueur gagne quand les coordonnées de l'escargot correspondent exactement à celles de l'arrivée.
Transformer le jeu en une vraie course d'escargots où plusieurs concurrents avancent automatiquement avec un système de fatigue.
On reprend le concept du tutorial précédent (preoo-01-menu) pour configurer la course via deux variables issues des options du menu :
// Ces variables pourraient venir du menu Options
int numberOfSnails = 4; // Nombre d'escargots dans la course
int raceSpeed = 100; // Délai en ms entre chaque mouvement (100 = rapide, 300 = lent)
Chaque escargot a une énergie qui diminue au fil de la course :
Énergie haute Énergie moyenne Énergie basse
@→ @→? @...
100% 50% 10%
// ========== CONFIGURATION (depuis le menu) ==========
int numberOfSnails = 4; // Option: nombre d'escargots
int raceSpeed = 150; // Option: vitesse (ms entre mouvements)
// ========== CONSTANTES DU JEU ==========
int screenWidth = 60;
int screenHeight = 3 + numberOfSnails * 2; // Adapté au nombre d'escargots
int startX = 2;
int finishX = screenWidth - 3;
// ========== DONNÉES DES ESCARGOTS (tableaux parallèles) ==========
int[] snailX = new int[numberOfSnails]; // Position X de chaque escargot
int[] snailY = new int[numberOfSnails]; // Position Y (ligne de course)
int[] snailEnergy = new int[numberOfSnails]; // Énergie (0-100)
string[] snailNames = new string[numberOfSnails];
ConsoleColor[] snailColors = { ConsoleColor.Yellow, ConsoleColor.Cyan,
ConsoleColor.Magenta, ConsoleColor.Green,
ConsoleColor.Red, ConsoleColor.Blue };
// ========== INITIALISATION ==========
Console.Clear();
Console.CursorVisible = false;
Random random = new Random();
// Initialiser chaque escargot
for (int i = 0; i < numberOfSnails; i++)
{
snailX[i] = startX;
snailY[i] = 2 + i * 2; // Chaque escargot sur sa ligne
snailEnergy[i] = 100; // Pleine énergie au départ
snailNames[i] = $"Snail {i + 1}";
}
// Dessiner le terrain
Race_DrawTrack();
Race_DrawAllSnails();
Race_ShowStatus();
Console.SetCursorPosition(0, screenHeight + 2);
Console.WriteLine("Press ENTER to start the race!");
Console.ReadLine();
// ========== BOUCLE DE COURSE ==========
bool raceFinished = false;
int winner = -1;
while (!raceFinished)
{
// Déplacer chaque escargot
for (int i = 0; i < numberOfSnails; i++)
{
// L'escargot avance seulement si son énergie le permet
int chanceToMove = snailEnergy[i]; // 100 = toujours, 50 = 1/2, etc.
if (random.Next(100) < chanceToMove)
{
// Effacer ancienne position
Snail_Clear(snailX[i], snailY[i]);
// Avancer (X augmente = vers la droite)
snailX[i] = snailX[i] + 1;
// Dessiner nouvelle position
Snail_DrawColored(snailX[i], snailY[i], snailColors[i % snailColors.Length]);
// Réduire l'énergie (fatigue)
snailEnergy[i] = snailEnergy[i] - random.Next(1, 4); // Perd 1-3 énergie
if (snailEnergy[i] < 5) snailEnergy[i] = 5; // Minimum 5% pour ne jamais s'arrêter totalement
}
// Vérifier si cet escargot a gagné
if (snailX[i] >= finishX)
{
winner = i;
raceFinished = true;
break;
}
}
Race_ShowStatus();
Thread.Sleep(raceSpeed); // Pause entre les tours
}
// ========== FIN DE COURSE ==========
Console.SetCursorPosition(0, screenHeight + 4);
Console.ForegroundColor = snailColors[winner % snailColors.Length];
Console.WriteLine($"{snailNames[winner]} WINS THE RACE!");
Console.ResetColor();
Console.ReadKey();
// ========== FONCTIONS DE COURSE ==========
void Race_DrawTrack()
{
for (int i = 0; i < numberOfSnails; i++)
{
int y = 2 + i * 2;
// Ligne de départ
Console.SetCursorPosition(startX - 1, y);
Console.ForegroundColor = ConsoleColor.White;
Console.Write("|");
// Piste (pointillés)
for (int x = startX; x < finishX; x++)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.Write(".");
}
// Ligne d'arrivée
Console.SetCursorPosition(finishX, y);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("|");
}
Console.ResetColor();
}
void Race_DrawAllSnails()
{
for (int i = 0; i < numberOfSnails; i++)
{
Snail_DrawColored(snailX[i], snailY[i], snailColors[i % snailColors.Length]);
}
}
void Race_ShowStatus()
{
Console.SetCursorPosition(0, screenHeight + 1);
Console.Write("Energy: ");
for (int i = 0; i < numberOfSnails; i++)
{
Console.ForegroundColor = snailColors[i % snailColors.Length];
Console.Write($"[{snailNames[i]}:{snailEnergy[i],3}%] ");
}
Console.ResetColor();
}
void Snail_DrawColored(int x, int y, ConsoleColor color)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = color;
Console.Write("@");
Console.ResetColor();
}
void Snail_Clear(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.Write("."); // Redessine la piste
Console.ResetColor();
}
On utilise plusieurs tableaux avec le même index pour stocker les données de chaque escargot :
// Index 0 = Snail 1, Index 1 = Snail 2, etc.
int[] snailX = { 2, 2, 2, 2 }; // Positions X
int[] snailY = { 2, 4, 6, 8 }; // Positions Y
int[] snailEnergy = { 100, 100, 100, 100 }; // Énergies
0 | 2 | 2 | 100 |
1 | 2 | 4 | 100 |
2 | 2 | 6 | 100 |
3 | 2 | 8 | 100 |
if (random.Next(100) < chanceToMove)
random.Next(100) génère un nombre entre 0 et 99chanceToMove = 100, la condition est toujours vraie (0-99 < 100)chanceToMove = 50, la condition est vraie une fois sur deuxchanceToMove = 10, l'escargot avance rarementPermettre au joueur d'interagir pendant la course pour aider son escargot favori.
Le joueur peut :

Encourager | ESPACE | +10 énergie pour l'escargot du joueur |
Placer salade | S | Crée un bonus sur la piste |
Quitter | ESC | Arrête la course |
// ========== CONFIGURATION ==========
int numberOfSnails = 4;
int raceSpeed = 120;
int playerSnailIndex = 0; // Le joueur contrôle l'escargot 0
// ========== CONSTANTES ==========
int screenWidth = 60;
int screenHeight = 3 + numberOfSnails * 2;
int startX = 2;
int finishX = screenWidth - 3;
// ========== DONNÉES DES ESCARGOTS ==========
int[] snailX = new int[numberOfSnails];
int[] snailY = new int[numberOfSnails];
int[] snailEnergy = new int[numberOfSnails];
string[] snailNames = new string[numberOfSnails];
ConsoleColor[] snailColors = { ConsoleColor.Yellow, ConsoleColor.Cyan,
ConsoleColor.Magenta, ConsoleColor.Green };
// ========== SALADES (bonus) ==========
int maxSalads = 5;
int[] saladX = new int[maxSalads];
int[] saladY = new int[maxSalads];
bool[] saladActive = new bool[maxSalads];
int saladCount = 0;
int playerSaladsRemaining = 3; // Le joueur peut placer 3 salades
// ========== INITIALISATION ==========
Console.Clear();
Console.CursorVisible = false;
Random random = new Random();
for (int i = 0; i < numberOfSnails; i++)
{
snailX[i] = startX;
snailY[i] = 2 + i * 2;
snailEnergy[i] = 100;
snailNames[i] = (i == playerSnailIndex) ? "YOU" : $"CPU {i}";
}
// Initialiser les salades comme inactives
for (int i = 0; i < maxSalads; i++)
{
saladActive[i] = false;
}
Race_DrawTrack();
Race_DrawAllSnails();
Race_ShowStatus();
Race_ShowControls();
Console.SetCursorPosition(0, screenHeight + 5);
Console.ForegroundColor = snailColors[playerSnailIndex];
Console.WriteLine($"You control: {snailNames[playerSnailIndex]} (@)");
Console.ResetColor();
Console.WriteLine("Press ENTER to start!");
Console.ReadLine();
// ========== BOUCLE DE COURSE ==========
bool raceFinished = false;
int winner = -1;
DateTime lastUpdate = DateTime.Now;
while (!raceFinished)
{
// Gérer les entrées clavier (non-bloquant)
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.Spacebar:
// Encourager = boost d'énergie
snailEnergy[playerSnailIndex] = snailEnergy[playerSnailIndex] + 10;
if (snailEnergy[playerSnailIndex] > 100)
snailEnergy[playerSnailIndex] = 100;
Race_ShowBoostEffect();
break;
case ConsoleKey.S:
// Placer une salade devant son escargot
if (playerSaladsRemaining > 0)
{
Race_PlaceSalad(snailX[playerSnailIndex] + 5, snailY[playerSnailIndex]);
playerSaladsRemaining--;
}
break;
case ConsoleKey.Escape:
raceFinished = true;
break;
}
}
// Mettre à jour la course à intervalle régulier
if ((DateTime.Now - lastUpdate).TotalMilliseconds >= raceSpeed)
{
lastUpdate = DateTime.Now;
for (int i = 0; i < numberOfSnails; i++)
{
int chanceToMove = snailEnergy[i];
if (random.Next(100) < chanceToMove)
{
Snail_Clear(snailX[i], snailY[i]);
snailX[i] = snailX[i] + 1;
// Vérifier si l'escargot mange une salade
Race_CheckSaladCollision(i);
Snail_DrawColored(snailX[i], snailY[i], snailColors[i]);
// Fatigue
snailEnergy[i] = snailEnergy[i] - random.Next(1, 4);
if (snailEnergy[i] < 5) snailEnergy[i] = 5;
}
if (snailX[i] >= finishX)
{
winner = i;
raceFinished = true;
break;
}
}
Race_ShowStatus();
}
Thread.Sleep(10); // Petit délai pour ne pas surcharger le CPU
}
// ========== RÉSULTAT ==========
Console.SetCursorPosition(0, screenHeight + 7);
if (winner == playerSnailIndex)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("VICTORY! Your snail won the race!");
}
else if (winner >= 0)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"{snailNames[winner]} won. Better luck next time!");
}
else
{
Console.WriteLine("Race cancelled.");
}
Console.ResetColor();
Console.ReadKey();
// ========== FONCTIONS ==========
void Race_DrawTrack()
{
for (int i = 0; i < numberOfSnails; i++)
{
int y = 2 + i * 2;
Console.SetCursorPosition(startX - 1, y);
Console.ForegroundColor = ConsoleColor.White;
Console.Write("|");
for (int x = startX; x < finishX; x++)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.Write(".");
}
Console.SetCursorPosition(finishX, y);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("|");
}
Console.ResetColor();
}
void Race_DrawAllSnails()
{
for (int i = 0; i < numberOfSnails; i++)
{
Snail_DrawColored(snailX[i], snailY[i], snailColors[i]);
}
}
void Race_ShowStatus()
{
Console.SetCursorPosition(0, screenHeight + 1);
for (int i = 0; i < numberOfSnails; i++)
{
Console.ForegroundColor = snailColors[i];
string bar = new string('█', snailEnergy[i] / 10);
string empty = new string('░', 10 - snailEnergy[i] / 10);
Console.Write($"{snailNames[i],4}[{bar}{empty}] ");
}
Console.ResetColor();
}
void Race_ShowControls()
{
Console.SetCursorPosition(0, screenHeight + 3);
Console.WriteLine($"SPACE=Boost | S=Salad ({playerSaladsRemaining} left) | ESC=Quit");
}
void Race_ShowBoostEffect()
{
int y = snailY[playerSnailIndex];
Console.SetCursorPosition(snailX[playerSnailIndex] + 1, y);
Console.ForegroundColor = ConsoleColor.White;
Console.Write("!");
Thread.Sleep(50);
Console.SetCursorPosition(snailX[playerSnailIndex] + 1, y);
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.Write(".");
}
void Race_PlaceSalad(int x, int y)
{
// Trouver un slot libre pour la salade
for (int i = 0; i < maxSalads; i++)
{
if (!saladActive[i])
{
saladX[i] = x;
saladY[i] = y;
saladActive[i] = true;
saladCount++;
// Dessiner la salade
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("$"); // $ = salade
Console.ResetColor();
Race_ShowControls(); // Mettre à jour le compteur
break;
}
}
}
void Race_CheckSaladCollision(int snailIndex)
{
for (int i = 0; i < maxSalads; i++)
{
if (saladActive[i] && saladX[i] == snailX[snailIndex] && saladY[i] == snailY[snailIndex])
{
// L'escargot mange la salade = gros boost !
snailEnergy[snailIndex] = snailEnergy[snailIndex] + 25;
if (snailEnergy[snailIndex] > 100) snailEnergy[snailIndex] = 100;
saladActive[i] = false;
saladCount--;
}
}
}
void Snail_DrawColored(int x, int y, ConsoleColor color)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = color;
Console.Write("@");
Console.ResetColor();
}
void Snail_Clear(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.Write(".");
Console.ResetColor();
}
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
// Traiter la touche...
}
Contrairement à Console.ReadKey() seul, Console.KeyAvailable vérifie s'il y a une touche sans bloquer le programme.
if ((DateTime.Now - lastUpdate).TotalMilliseconds >= raceSpeed)
{
lastUpdate = DateTime.Now;
// Mettre à jour le jeu...
}
Permet de contrôler la vitesse du jeu indépendamment de la boucle principale.
Les salades utilisent aussi des tableaux parallèles :
saladX[] : position XsaladY[] : position YsaladActive[] : la salade existe-t-elle encore ?Modifier le système pour que les appuis rapides sur ESPACE soient plus efficaces :
DateTime lastBoostTime = DateTime.MinValue;
int comboCount = 0;
// Dans le traitement de ESPACE :
TimeSpan timeSinceLastBoost = DateTime.Now - lastBoostTime;
if (timeSinceLastBoost.TotalMilliseconds < 500)
{
comboCount++;
int boostAmount = 5 + comboCount * 2; // Combo = plus de boost !
}
else
{
comboCount = 0;
}
lastBoostTime = DateTime.Now;
// Obstacle positions
int[] obstacleX = { 15, 20, 25, 30 };
int[] obstacleY = { 5, 8, 6, 10 };
void Game_DrawObstacles()
{
Console.ForegroundColor = ConsoleColor.Red;
for (int i = 0; i < obstacleX.Length; i++)
{
Console.SetCursorPosition(obstacleX[i], obstacleY[i]);
Console.Write("X");
}
Console.ResetColor();
}
bool Game_IsObstacle(int x, int y)
{
for (int i = 0; i < obstacleX.Length; i++)
{
if (obstacleX[i] == x && obstacleY[i] == y)
{
return true;
}
}
return false;
}
int moveCount = 0;
// Dans la boucle, après un déplacement valide :
moveCount++;
Game_ShowMoves(moveCount);
void Game_ShowMoves(int count)
{
Console.SetCursorPosition(30, screenHeight + 4);
Console.Write($"Moves: {count} ");
}
DateTime startTime = DateTime.Now;
// À la fin du jeu :
TimeSpan duration = DateTime.Now - startTime;
Console.WriteLine($"Time: {duration.TotalSeconds:F1} seconds");
void Snail_DrawFancy(int x, int y)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.SetCursorPosition(x, y);
Console.Write("@)"); // Simple snail
Console.ResetColor();
}
Console/Écran Mathématiques
============= =============
(0,0)----→ X (Left) Y ↑
| |
| |
↓ (0,0)----→ X
Y (Top)
Origine (0,0) | Haut-gauche | Bas-gauche |
X augmente | → droite | → droite |
Y augmente | ↓ bas | ↑ haut |
Flèche haut | Y– | Y++ |
Flèche bas | Y++ | Y– |
Comme pour le menu, ce code peut évoluer vers des classes :
public class Snail
{
private int x;
private int y;
private int energy;
private ConsoleColor color;
private string name;
public void Draw() { ... }
public void Clear() { ... }
public void Move() { ... }
public void Boost(int amount) { ... }
}
public class Race
{
private Snail[] snails;
private Salad[] salads;
private int finishLine;
public void Start() { ... }
public void Update() { ... }
public Snail GetWinner() { ... }
}
Les tableaux parallèles (snailX[], snailY[], snailEnergy[]) deviennent naturellement des attributs d'une classe Snail !